package com.hornet.shiro.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;

import com.alibaba.fastjson.JSON;
import com.hornet.commons.constants.BaseConst;
import com.hornet.commons.spring.SpringContextHolder;
import com.hornet.commons.utils.SystemHelper;
import com.hornet.commons.web.model.AjaxResponse;

/**
 * ShiroCaptchaValidateFilter
 * 
 */
public class ShiroValidateCodeFilter extends AccessControlFilter {
	
	private boolean captchaEbabled = true; // 是否开启验证码支持
	private String validateParam = "validateCode"; // 前台提交的验证码参数名
	private int showCaptchaRetryCount = 3; // 验证出错次数显示验证码
	private String failureKeyAttribute = "shiroLoginFailure"; // 验证失败后存储到的属性名

	public void setCaptchaEbabled(final boolean captchaEbabledParm) {
		this.captchaEbabled = captchaEbabledParm;
	}

	public void setValidateParam(String validateParam) {
		this.validateParam = validateParam;
	}
	
	public void setShowCaptchaRetryCount(final int showCaptchaRetryCountParm) {
		this.showCaptchaRetryCount = showCaptchaRetryCountParm;
	}

	public void setFailureKeyAttribute(final String failureKeyAttributeParm) {
		this.failureKeyAttribute = failureKeyAttributeParm;
	}

	@Override
	protected boolean isAccessAllowed(final ServletRequest request, final ServletResponse response, final Object mappedValue) throws Exception {
		// 设置验证码是否开启属性，页面可以根据该属性来决定是否显示验证码
		request.setAttribute("captchaEbabled", captchaEbabled);
		HttpServletRequest httpServletRequest = WebUtils.toHttp(request);

		// 判断验证码是否禁用 或不是表单提交（允许访问）
		if (!captchaEbabled || !"post".equalsIgnoreCase(httpServletRequest.getMethod())) {
			return true;
		}
		AtomicInteger sessionRetryCount = (AtomicInteger) SystemHelper.getSession().getAttribute(BaseConst.SESSION_RETRY_COUNT);
		int sessionErrorCount = 0;
		if (sessionRetryCount != null) {
			sessionErrorCount = sessionRetryCount.get();
		}
		
		if (captchaEbabled && sessionErrorCount >= showCaptchaRetryCount) { // 验证验证码是否正确
			
			if(SpringContextHolder.getHttpSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY).equals(httpServletRequest.getParameter(validateParam))) {
				SystemHelper.removeSessionCaptchaRetryCount();
				return true ;
			} else {
				try {
					response.setCharacterEncoding("utf-8");
					PrintWriter writer = response.getWriter();
					AjaxResponse ajaxResponse = new AjaxResponse() ;
					ajaxResponse.setStatus(false);
					ajaxResponse.setMessage("验证码不正确！");
					
					SystemHelper.setSessionCaptchaRetryCount(SystemHelper.getSessionCaptchaRetryCount()+1 );
					
					HashMap<String, Object> map = new HashMap<String, Object>() ;
					//显示验证码验证验证码
					map.put("showValidateCode", true);
					//刷新验证码
					map.put("resetValidateCode", SystemHelper.getSessionCaptchaRetryCount()%3==0?true:false);
					
					ajaxResponse.setObj(map);
					
					writer.write(JSON.toJSONString(ajaxResponse));
					writer.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
				return false;
			}
			
		} else {
			return true;
		}
	}

	@Override
	protected boolean onAccessDenied(final ServletRequest request, final ServletResponse response) throws Exception {
		// 如果验证码失败了，存储失败key属性
		request.setAttribute(failureKeyAttribute, "captcha.error");
		return false;
	}
}
